﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;

namespace ClientLocker.Utility
{
    #region 消息结构体(参照WinUser.h中定义)#region 消息结构体(参照WinUser.h中定义)
    public struct CWPSTRUCT
    {
        public IntPtr lparam;
        public IntPtr wparam;
        public int message;
        public IntPtr hwnd;
    }
    #endregion

    #region 钩子类型的枚举#region 钩子类型的枚举
    public enum HookType : int
    {
        WH_JOURNALRECORD = 0,
        WH_JOURNALPLAYBACK = 1,
        WH_KEYBOARD = 2,
        WH_GETMESSAGE = 3,
        WH_CALLWNDPROC = 4,
        WH_CBT = 5,
        WH_SYSMSGFILTER = 6,
        WH_MOUSE = 7,
        WH_HARDWARE = 8,
        WH_DEBUG = 9,
        WH_SHELL = 10,
        WH_FOREGROUNDIDLE = 11,
        WH_CALLWNDPROCRET = 12,
        WH_KEYBOARD_LL = 13,
        WH_MOUSE_LL = 14
    }
    #endregion

    #region 虚键值的定义(参照WinUser.h中定义)#region 虚键值的定义(参照WinUser.h中定义)
    public enum VirtualKeys
    {
        VK_SHIFT = 0x10,
        VK_CONTROL = 0x11,
        VK_MENU = 0x12,    //ALT
        VK_PAUSE = 0x13,
        VK_CAPITAL = 0x14
    }
    #endregion

    #region 钩子委托#region 钩子委托
    public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
    public delegate void HookEventHandler(object sender, HookEventArgs e);
    #endregion

    #region 钩子事件参数#region 钩子事件参数
    public class HookEventArgs : EventArgs
    {
        public int HookCode;
        public IntPtr wParam;
        public IntPtr lParam;
        public Keys key;
        public bool bAltKey;
        public bool bCtrlKey;
    }
    #endregion

    #region 钩子类#region 钩子类
    public class FCHook
    {
        #region 调用Windows API#region 调用Windows API
        [DllImport("user32.dll", SetLastError=true)]
        static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern short GetKeyState(VirtualKeys nVirtKey);
        #endregion

        #region 局部变量#region 局部变量
        private IntPtr m_hook;
        private HookType m_hooktype;
        private HookProc m_hookproc;

        private bool _bCallNext;

        public bool CallNextProc
        {
            get { return _bCallNext; }
            set { _bCallNext = value; }
        }

        #endregion

        public event HookEventHandler HookInvoked;

        public void Install()
        {
            m_hook = SetWindowsHookEx(m_hooktype, m_hookproc, IntPtr.Zero, 0);
            if (m_hook.ToString() == "0")
            {
                Debug.WriteLine("Last Win32 Error: " + Marshal.GetLastWin32Error());
            }
        }

        public void Uninstall()
        {
            if (m_hook != IntPtr.Zero)
            {
                UnhookWindowsHookEx(m_hook);
            }
        }

        public FCHook(HookType HookType)
        {
            m_hooktype = HookType;
            if (m_hooktype == HookType.WH_KEYBOARD || m_hooktype == Utility.HookType.WH_KEYBOARD_LL)
            {
                m_hookproc = new HookProc(KeyHookProcedure);
            }
            else if (m_hooktype == HookType.WH_CALLWNDPROC)
            {
                m_hookproc = new HookProc(CallProcHookProcedure);
            }
        }

        protected int KeyHookProcedure(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code != 0)
            {
                return CallNextHookEx(m_hook, code, wParam, lParam);
            }

            if (HookInvoked != null)
            {
                Keys key = (Keys)wParam.ToInt32();
                HookEventArgs eventArgs = new HookEventArgs();
                eventArgs.key = key;
                eventArgs.lParam = lParam;
                eventArgs.wParam = wParam;
                eventArgs.HookCode = code;
                eventArgs.bAltKey = GetKeyState(VirtualKeys.VK_MENU) <= -127;
                eventArgs.bCtrlKey = GetKeyState(VirtualKeys.VK_CONTROL) <= -127;
                HookInvoked(this, eventArgs);
            }

            return this.CallNextProc ? CallNextHookEx(m_hook, code, wParam, lParam) : 1;
        }

        public struct KeyboardMSG
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;

        }
        
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
        public static extern short GetKeyState(int keycode);
        protected int CallProcHookProcedure(int code, IntPtr wParam, IntPtr lParam)
        {
            try
            {

                KeyboardMSG m = (KeyboardMSG)Marshal.PtrToStructure(lParam, typeof(KeyboardMSG));
                if (HookInvoked != null)
                {
                    HookEventArgs eventArgs = new HookEventArgs();
                    eventArgs.lParam = lParam;
                    eventArgs.wParam = wParam;
                    eventArgs.HookCode = code;
                    HookInvoked(this, eventArgs);
                }
                if (CallNextProc)
                {
                    return CallNextHookEx(m_hook, code, wParam, lParam);
                }
                else
                {
                    //return 1;
                    CallNextProc = true;
                    return 1;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return 0;
            }
        }
    }
    #endregion
}
